#include "libMontador.h"

int main() {

    programCounter = 0;
    sybolCounter = 0;
    fileLine = 0;
    tokenCounter = 0;
    errorCounter = 0;
    numOperandos = 0;
    locSTOP = FALSE;

    for (numOperandos = 0; numOperandos < MEMORIA; numOperandos++) {
        REALOC[numOperandos] = FALSE;
    }

    numOperandos = 0;

    FILE * arquivoFonte;
    size_t tamanhoArquivo = 100;

    inicializaTabInstrucoes();

    arquivoFonte = openFile();

    fseek(arquivoFonte, 0, SEEK_SET);

    char * linha = malloc(sizeof (char) * tamanhoArquivo);

    if (linha == NULL) {
        armazenaErro("Falha ao criar buffer de leitura para arquivo", fileLine);
        finalizaPrograma(EXIT_FAILURE);
    }

    do {
        if (fgets(linha, tamanhoArquivo, arquivoFonte)) {

            fileLine++;

            char * token = trataLinha(linha);
            if (token == NULL) {
                armazenaErro("Erro de sintaxe", fileLine);
            }
            int instrucaoGravada = FALSE;
            tokenCounter = 0;
            while (token) {
                int indiceInstrucao = FALSE;
                token = strToUpper(token);

                indiceInstrucao = buscaInstrucao(token);

                if (indiceInstrucao != FALSE) {
                    if (instrucaoGravada == TRUE) {
                        armazenaErro("Esperado um operando, encontrado uma instrução", fileLine);
                    } else {
                        gravaInstrucao(indiceInstrucao);
                        numOperandos = TabInstrucoes[indiceInstrucao].operandos;
                        if (TabInstrucoes[indiceInstrucao].codigo == STOP) {
                            locSTOP = TRUE;
                        }
                        instrucaoGravada = TRUE;
                    }
                } else if (token[0] >= '0' && token[0] <= '9') {
                    if (instrucaoGravada == TRUE) {
                        if (numOperandos == 0) {
                            armazenaErro("Operando excedente", fileLine);
                            numOperandos = 0;
                        } else {
                            if (isNumber(token) == FALSE) {
                                armazenaErro("Endereço inválido", fileLine);
                            } else {
                                gravaEndereco(token);
                                numOperandos--;
                            }
                        }
                    } else {
                        armazenaErro("Esperado uma instrução ou um label", fileLine);
                    }
                } else {
                    if (tokenCounter >= 1 && instrucaoGravada == FALSE) {
                        armazenaErro("Esperado uma instrução", fileLine);
                    } else {
                        if (tokenCounter == 0) {
                            if (gravaSimboloMatriz(token) == FALSE) {
                                armazenaErro("Dupla definição de label encontrada", fileLine);
                            }
                        } else {
                            if (numOperandos == 0) {
                                armazenaErro("Operando excedente", fileLine);
                                numOperandos = 0;
                            } else {
                                gravaSimboloSaida(token);
                                numOperandos--;
                            }
                        }
                    }
                }
                token = strtok(NULL, " ");
                tokenCounter++;
            }
            if (numOperandos > 0) {
                armazenaErro("Esperado um operando", fileLine);
                numOperandos = 0;
            }
        }
    } while (!feof(arquivoFonte));

    if (linha) {
        free(linha);
    }

    fclose(arquivoFonte);

    if (locSTOP == FALSE) {
        armazenaErro("Instrução de finalização não encontrada.", fileLine);
    }

    if (errorCounter > 0) {
        finalizaPrograma(EXIT_FAILURE);
    }

    segundaPassagem();

    if (errorCounter > 0) {
        finalizaPrograma(EXIT_FAILURE);
    }

    if (criaArquivoBin() == TRUE) {
        printf("Arquivo binario gerado com sucesso\n");
        finalizaPrograma(EXIT_SUCCESS);
    } else {
        printf("Não foi possível gravar arquivo binário\n");
        finalizaPrograma(EXIT_FAILURE);
    }

}